<?php


namespace App\Controller;


class tcpserver
{
    public function onTcpReceive($serv, $fd, $from_id, $data)

    {
        $receive = $data;
        $num = rand(0, 10);// 随机数(保留)
        $address = $receive[4];// 控制器地址(保留)
        $door = $receive[5];// 门编号
        $command = $receive[3];//指令先用控制器里发来的
        // 包头
        $pack_head = [
            "02",
            $num,
            $command,
            $address,
            $door,
        ];
        // 包体
        $pack_body = [
            $command
        ];
        $sendData = $this->getSendData($pack_head, $pack_body);
        return $sendData;
    }

    function getSendData(array $head, array $body = array())
    {
        $length = count($body);// 包体长度
        $hight = ($length & 0xff00) >> 8;// 高位右移8个位
        $low = $length & 0x00ff;// 低位
        $head[] = $low;// 数据长度低位
        $head[] = $hight;// 数据长度高位
        // 将包头和包体 合并
        $data = $body ? array_merge_recursive($head, $body) : $head;
        $check = $this->getCheckVal($data);// 获取校验值
        $data[] = $check;
        $data[] = "03";
        return $this->get_pack($data);
    }

    function get_pack($data)

    {
        $pack = "";
        foreach ($data as $k => $d) {
            $pack .= pack("C*", $d);// 十六进制应答
        }
        // echo "十六进制转为字符串应答的数据：" . bin2hex($pack) . PHP_EOL;
        return $pack;

    }
    /**
     * 根据数组中所有值 获取校验值
     * @param array $data
     * @return float|int|string
     */

    function getCheckVal(array $data)

    {
        // 将第一个放进循环中会报错，单独将第一个字节先取出来
        $check = hexdec("0x" . $data[0]);
        // 所有数据 进行异或运算，从数组中的第二个开始 (测试数据，减掉包尾)
        $i = 0;
        // 这里的data是十六进制的字符串，要先将它以0x组合出来16进制的字符串，再转换为10进制的数字用以运算
        // 得到的结果是十进制的校验值
        foreach ($data as $d) {
            $i++;
            //echo "打印加入运算的字符：" . $d.PHP_EOL;
            if ($i == 1) {
                $check = $d;
            } else {
                $check ^= $d;
            }
        }
        // check = dechex($check); // 结果：是十进制的，最后，将十进制转十六进制字符，这里不需要转换十六进制，因为最后还需要将数据放到pack方法中转换
        return $check;
    }
}
